#include "../../MyUtils/DataType/Array.hpp"
// #include "../../MyUtils/tools.hpp"
#include <gtest/gtest.h>

typedef unsigned long long T;
typedef MyUtils::DataType::Array< T > ByteArray;

using namespace std;

TEST( TEST_Array, ByteArray )
{
    ByteArray a; // default constructor
    EXPECT_EQ( a.size( ), 0 );
    EXPECT_EQ( a.capacity( ), 512 );
    EXPECT_NE( a.data( ), nullptr );

    ByteArray b( size_t(0), size_t(1024) ); // constructor with size
    EXPECT_EQ( b.size( ), 0 );
    EXPECT_EQ( b.capacity( ), 1024 );
    EXPECT_NE( b.data( ), nullptr );
    memset( ( void * ) b.data( ), 1, b.capacity( ) * sizeof( T ) );
    T val;
    memset( &val, 1, sizeof( T ) );
    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( b.data( ) ) )[ i ], val );
    }

    ByteArray c( std::move( b ) ); // move constructor
    EXPECT_EQ( c.size( ), 0 );
    EXPECT_EQ( c.capacity( ), 1024 );
    EXPECT_NE( c.data( ), nullptr );
    EXPECT_EQ( b.size( ), 0 );
    EXPECT_EQ( b.capacity( ), 0 );
    EXPECT_EQ( b.data( ), nullptr );
    EXPECT_NE( b.data( ), c.data( ) );
    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( c.data( ) ) )[ i ], 1 );
    }

    ByteArray d( c ); // shadow copy constructor
    EXPECT_EQ( d.size( ), 0 );
    EXPECT_EQ( d.capacity( ), 1024 );
    EXPECT_NE( d.data( ), nullptr );
    EXPECT_EQ( c.size( ), 0 );
    EXPECT_EQ( c.capacity( ), 1024 );
    EXPECT_NE( c.data( ), nullptr );
    EXPECT_EQ( d.data( ), c.data( ) );
    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( d.data( ) ) )[ i ], 1 );
    }

    ByteArray e = d; // asignment constructor, shadow copy
    EXPECT_EQ( e.size( ), 0 );
    EXPECT_EQ( e.capacity( ), 1024 );
    EXPECT_NE( e.data( ), nullptr );
    EXPECT_EQ( d.size( ), 0 );
    EXPECT_EQ( d.capacity( ), 1024 );
    EXPECT_NE( d.data( ), nullptr );
    EXPECT_EQ( e.data( ), d.data( ) );
    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( e.data( ) ) )[ i ], 1 );
    }

    ByteArray f( e.data( ), e.capacity( ) ); // move assignment
    EXPECT_EQ( f.size( ), e.capacity( ) );
    EXPECT_EQ( f.capacity( ), e.capacity( ) );
    EXPECT_NE( f.data( ), e.data( ) );
    EXPECT_NE( f.data( ), nullptr );

    ByteArray g;
    g = e; // asignment
    EXPECT_EQ( g.size( ), e.size( ) );
    EXPECT_EQ( g.capacity( ), e.capacity( ) );
    EXPECT_EQ( g.data( ), e.data( ) );

    ByteArray h = g.clone( ); // deep copy
    EXPECT_EQ( h.size( ), g.size( ) );
    // EXPECT_EQ( h.capacity( ), g.capacity( ) );//不一定
    EXPECT_NE( h.data( ), g.data( ) );
    EXPECT_NE( h.data( ), nullptr );
    for ( int i = 0; i < g.size( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( h.data( ) ) )[ i ],
                   ( ( T * ) ( g.data( ) ) )[ i ] );
    }
}

TEST( TEST_Array, ByteArray_copy )
{
    ByteArray a( size_t(0), 1024 );
    memset( ( void * ) a.data( ), 1, a.capacity( ) * sizeof( T ) );

    ByteArray b( a ); // shadow copy
    EXPECT_EQ( b.size( ), 0 );
    EXPECT_EQ( b.capacity( ), a.capacity( ) );
    EXPECT_EQ( b.data( ), a.data( ) );

    T val;
    memset( &val, 1, sizeof( T ) );
    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( b.data( ) ) )[ i ], val );
    }

    ByteArray c;
    c.copy( b ); // copy
    EXPECT_EQ( c.size( ), b.size( ) );
    // EXPECT_EQ( c.capacity( ), b.capacity( ) );//二者不一定相等
    EXPECT_NE( c.data( ), b.data( ) ); //二者一定不相等
    memset( ( void * ) c.data( ), 2, c.capacity( ) * sizeof( T ) );

    memset( &val, 1, sizeof( T ) );
    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( b.data( ) ) )[ i ], val );
    }
    memset( &val, 2, sizeof( T ) );

    for ( int i = 0; i < c.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( c.data( ) ) )[ i ], val );
    }

    T d[] = { 'h', 'e', 'l', 'l', 'o' };
    size_t len = sizeof( d ) / sizeof( T );
    ByteArray e( d, len );
    EXPECT_EQ( e.size( ), len );
    EXPECT_EQ( e.capacity( ),
               8 ); // strlen( d ) == 5，不是2的指数，将其扩增到2的指数
    EXPECT_NE( e.data( ), nullptr );
    EXPECT_NE( ( void * ) e.data( ), ( void * ) d );

    ByteArray f = e.clone( ); // deep copy
    EXPECT_EQ( f.size( ), e.size( ) );
    EXPECT_EQ( f.capacity( ), e.capacity( ) );
    EXPECT_EQ( f.capacity( ),
               8 ); //默认初始化为512，e.size() == 5 < 512，容量不变
    EXPECT_NE( f.data( ), e.data( ) );

    T g[ 1023 ];
    memset( g, 1, 1023 * sizeof( T ) );
    ByteArray h;
    h.copy( g, 1020 ); // copy
    EXPECT_EQ( h.size( ), 1020 );
    EXPECT_EQ( h.capacity( ),
               1024 ); //默认初始化为512，容量需要扩增到最近的2的指数即1024
}

TEST( TEST_Array, ByteArray_append )
{
    ByteArray a( 1024 );
    memset( ( void * ) a.data( ), 1, a.capacity( ) * sizeof( T ) );
    EXPECT_EQ( a.capacity( ), 1024 );
    EXPECT_EQ( a.size( ), 1024 );
    EXPECT_NE( a.data( ), nullptr );
    a.setDataLen( 0 );
    EXPECT_EQ( a.size( ), 0 );
    EXPECT_EQ( a.capacity( ), 1024 );
    EXPECT_NE( a.data( ), nullptr );

    ByteArray b( a ); // shadow copy
    EXPECT_EQ( b.size( ), a.size( ) );
    EXPECT_EQ( b.capacity( ), a.capacity( ) );
    EXPECT_EQ( b.data( ), a.data( ) );

    T val;
    memset( ( void * ) &val, 1, sizeof( T ) );

    for ( int i = 0; i < b.capacity( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( b.data( ) ) )[ i ], val );
    }

    b.setDataLen( 0 );
    T c[] = { 'h', 'l', 'l', 'o' };
    b.append( c, sizeof( c ) / sizeof( T ) );
    EXPECT_EQ( b.size( ), sizeof( c ) / sizeof( T ) );
    EXPECT_EQ( b.size( ), a.size( ) );
    EXPECT_EQ( b.capacity( ), a.capacity( ) );
    EXPECT_EQ( b.data( ), a.data( ) );

    T d[] = { 'w', 'o', 'r', 'l', 'd' };
    b.append( d, sizeof( d ) / sizeof( T ) );
    EXPECT_EQ( b.size( ),
               sizeof( c ) / sizeof( T ) + sizeof( d ) / sizeof( T ) );
    EXPECT_EQ( b.size( ), a.size( ) );
    EXPECT_EQ( b.capacity( ), a.capacity( ) );
    EXPECT_EQ( b.data( ), a.data( ) );

    ByteArray e = ByteArray::append( c, sizeof( c ) / sizeof( T ), d,
                                     sizeof( d ) / sizeof( T ) );
    EXPECT_EQ( e.size( ),
               sizeof( c ) / sizeof( T ) + sizeof( d ) / sizeof( T ) );
    EXPECT_EQ( e.size( ), a.size( ) );
}

TEST( TEST_Array, ByteArray_swap )
{
    T hi[] = { 'h', 'i' };
    T world[] = { 'w', 'o', 'r', 'l', 'd' };
    ByteArray a{ hi, sizeof( hi ) / sizeof( T ) };
    ByteArray b( world, sizeof( world ) / sizeof( T ) );
    a.swap( b );
    EXPECT_EQ( a.size( ), sizeof( world ) / sizeof( T ) );
    EXPECT_EQ( b.size( ), sizeof( hi ) / sizeof( T ) );

    for(int i = 0; i < a.size( ); ++i)
    {
        EXPECT_EQ( a.data( )[ i ], world[ i ] );
    }
    for(int i = 0; i < b.size( ); ++i)
    {
        EXPECT_EQ( b.data( )[ i ], hi[ i ] );
    }
}

TEST( TEST_Array, ByteArray_clear )
{
    T hi[] = { 'h', 'e', 'l', 'l', 'o' };
    ByteArray a( hi, 5 );
    auto b = a;
    a.clear( );
    EXPECT_EQ( a.size( ), 0 );
    EXPECT_EQ( a.capacity( ), 8 );
    EXPECT_NE( a.data( ), nullptr );

    EXPECT_EQ( b.size( ), a.size( ) );
    EXPECT_EQ( b.capacity( ), a.capacity( ) );
    EXPECT_EQ( b.data( ), a.data( ) );
}

TEST( TEST_Array, ByteArray_slice )
{
    ByteArray a( 11 );
    for ( int i = 0; i < 11; ++i )
    {
        a.data( )[ i ] = i;
    }
    ByteArray b = a.slice( 1, 6 );
    EXPECT_EQ( b.size( ), 5 );
    EXPECT_EQ( b.capacity( ), 8 );
    EXPECT_NE( b.data( ), nullptr );
    EXPECT_NE( b.data( ), a.data( ) );
    for ( int i = 0; i < b.size( ); ++i )
    {
        EXPECT_EQ( b.data( )[ i ], i + 1 );
        b.data( )[ i ] = 0;
    }
    for ( int i = 0; i < a.size( ); ++i )
    {
        EXPECT_EQ( ( ( T * ) ( a.data( ) ) )[ i ], i );
    }
    return;
}

TEST( TEST_Array, ByteArray_append_char_and_index )
{
    ByteArray a;
    a.append( 'a' );
    a.append( 'b' );
    a.append( 'c' );
    a.append( 'd' );
    a.append( 'e' );
    a.append( 'f' );
    a.append( 'g' );

    EXPECT_EQ( a.size( ), 7 );
    EXPECT_EQ( a.capacity( ), 512 );
    EXPECT_NE( a.data( ), nullptr );
    EXPECT_EQ( a[ 0 ], 'a' );
    EXPECT_EQ( a[ 1 ], 'b' );
    EXPECT_EQ( a[ 2 ], 'c' );
    EXPECT_EQ( a[ 3 ], 'd' );
    EXPECT_EQ( a[ 4 ], 'e' );
    EXPECT_EQ( a[ 5 ], 'f' );
    EXPECT_EQ( a[ 6 ], 'g' );
}

TEST( TEST_Array, ByteArray_const)
{
    T hi[] = { 'h', 'e', 'l', 'l', 'o' };
    const ByteArray a( hi, 5 );
    EXPECT_EQ( a.size( ), 5 );
    EXPECT_EQ( a.capacity( ), 8 );

    // T* data = static_cast<T*>(a.data());//用static_cast进行将不会允许const限定符丢失，因此要善于使用static_cast
    // data[0] = 'a';

}
